package cn.dansj.plugin;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;

@Mojo(name = "transform", defaultPhase = LifecyclePhase.PROCESS_CLASSES, requiresDependencyResolution = ResolutionScope.COMPILE, threadSafe = true)
public class ConditionalOnClassTransformMojo extends AbstractMojo {
    @Parameter(defaultValue = "${project.build.outputDirectory}", property = "outputDirectory", required = true)
    private File outputDirectory;

    @Override
    public void execute() throws MojoExecutionException {
        getLog().info("[ ConditionalOnClassTransfer ] Starting annotation transformation...");
        getLog().info("Processing classes in: " + outputDirectory.getAbsolutePath());

        if (!outputDirectory.exists()) {
            getLog().warn("Output directory does not exist: " + outputDirectory);
            return;
        }

        try {
            long startTime = System.currentTimeMillis();
            List<Path> transformedFiles = transformClasses(outputDirectory.toPath());
            long duration = System.currentTimeMillis() - startTime;
            getLog().info("[ ConditionalOnClassTransfer ] Annotation transformation completed.");
            getLog().info("Transformed " + transformedFiles.size() + " classes in " + duration + "ms");
            if (!transformedFiles.isEmpty()) {
                getLog().info("Transformed files:");
                for (Path file : transformedFiles) {
                    getLog().info("  " + outputDirectory.toPath().relativize(file));
                }
            }
        } catch (IOException e) {
            throw new MojoExecutionException("Failed to transform classes", e);
        }
    }

    private List<Path> transformClasses(Path classesDir) throws IOException {
        List<Path> transformedFiles = new ArrayList<>();

        Files.walkFileTree(classesDir, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                if (file.toString().endsWith(".class")) {
                    if (transformClassFile(file)) {
                        transformedFiles.add(file);
                    }
                }
                return FileVisitResult.CONTINUE;
            }
        });
        return transformedFiles;
    }

    private boolean transformClassFile(Path classFile) {
        try {
            ConditionalOnClassTransformer transformer = new ConditionalOnClassTransformer();
            byte[] originalBytes = Files.readAllBytes(classFile);
            byte[] transformedBytes = transformer.transform(originalBytes);

            if (transformedBytes != null && transformedBytes.length > 0 && !bytesEqual(originalBytes, transformedBytes)) {
                Files.write(classFile, transformedBytes, StandardOpenOption.TRUNCATE_EXISTING);
                getLog().info("Transformed: " + classFile.getFileName());
                return true;
            }
        } catch (Exception e) {
            getLog().error("Error transforming class: " + classFile, e);
        }
        return false;
    }

    private boolean bytesEqual(byte[] a, byte[] b) {
        if (a.length != b.length) return false;
        for (int i = 0; i < a.length; i++) {
            if (a[i] != b[i]) return false;
        }
        return true;
    }
}